<?php
// +----------------------------------------------------------------------
// | Author: July
// +----------------------------------------------------------------------
// | 创建时间: 2023-12-27 20:39:42
// +----------------------------------------------------------------------
// | 角色相关操作
// +----------------------------------------------------------------------

namespace july\julyadmin\common\logic;

use july\julyadmin\common\model\AdminRoleList;
use july\julyadmin\common\model\Menu;

class AdminRoleLogic
{
    //上下文对象
    public $context;

    /**
     * 初始化
     * @param class $context 上下文对象，也就是调用当前类的this，通常传递$this即可
     */
    public function __construct($context)
    {
        $this->context = $context;
    }

    /**
     * 获取菜单和菜单下面的权限按钮数据
     * @Author   July
     * @DateTime 2024-01-13T20:09:14+0800
     * @param  integer  $parent_id      父id
     * @return array
     */
    public function getMenuPermissionsTree($parent_id = 0)
    {
        $order = 'id ASC';
        $data  = Menu::field('id,name AS text,controller,action,module')->where(['disabled' => 1, 'parent_id' => $parent_id])->order($order)->select()->toArray();
        foreach ($data as $dk => $dv) {
            if (!self::isHaveMenuPermission($dv['id'])) {
                unset($data[$dk]);
            }
        }
        $data = array_values($data);
        if ($data && is_array($data)) {
            foreach ($data as &$arr) {
                if ($arr['controller']) {
                    $arr['children'] = [];
                    $files           = [];
                    //从julyadmin获取控制器中的权限按钮
                    $files = $this->getControllers('../vendor/july/julyadmin/src/admin', $arr['controller'] . '.php');
                    //如果julyadmin中没有找到控制器，那么就从开发者的项目中找
                    if (!$files) {
                        $dir   = '../app';
                        $files = $this->getControllers($dir, $arr['controller'] . '.php');
                    }

                    if ($files) {
                        //从找到的控制器中匹配出命名空间
                        $controller = file_get_contents($files[0]);
                        //先临时把://替换成别的字符串，避免网址被替换掉
                        $controller = str_replace("://", ":/:/:/:/", $controller);
                        //替换掉控制器文件中的所有注释，避免下面获取权限按钮的时候获取到注释掉的权限按钮v
                        //删除EOT块
                        $controller = preg_replace('/<<<EOT[\s\S]*?EOT;/s', '', $controller);
                        //删除<script>块
                        $controller = preg_replace('/<script[\s\S]*?<\/script>/s', '', $controller);
                        //删除<style>块
                        $controller = preg_replace('/<style[\s\S]*?<\/style>/s', '', $controller);
                        //删除块注释
                        $controller = preg_replace('/\/\*\*[\s\S]*?\*\//s', '', $controller);
                        //删除行注释
                        $controller = preg_replace('~//(.*)+\n~', '', $controller);
                        //删除items这里的->show，避免被误判加进来
                        $controller = preg_replace('/->show\([\'items\'|\"items\"](.*?)/s', '', $controller);
                        //找到命名空间
                        $preg = '~namespace ([a-zA-Z\\\]+)~';
                        preg_match_all($preg, $controller, $res);
                        if (isset($res[1][0]) && $res[1][0]) {
                            //拼接控制器引用路径
                            $control = '\\' . $res[1][0] . "\\" . $arr['controller'];
                            request()->setController($arr['controller']);
                            //判断控制器中的方法是否存在，如果存在就执行，执行之后就能得到权限按钮数组
                            if (class_exists($control) && method_exists($control, 'index')) {
                                //通过正则表达式，匹配出控制器中的权限按钮，并进行拼装
                                $preg = '~((->addBtn|->editBtn|->deleteBtn|->disabledBtn|->linkBtn|->openWindowBtn|->viewBtn|->show)\(.*\))~';
                                preg_match_all($preg, $controller, $action_res);
                                if (isset($action_res[2]) && $action_res[2]) {
                                    foreach ($action_res[2] as $bk => $bv) {
                                        $params_preg = '~\((.*)\)~';
                                        preg_match_all($params_preg, $action_res[0][$bk], $params_res);
                                        $btn    = [];
                                        $params = array_filter(explode(',', $params_res[1][0]));
                                        $bv     = explode('->', $bv)[1];
                                        $module = $arr['module'];
                                        if (in_array($bv, ['addBtn', 'editBtn', 'disabledBtn', 'deleteBtn', 'viewBtn', 'show'])) {
                                            switch ($bv) {
                                                //如果是添加按钮
                                                case 'addBtn':
                                                    if (self::isHaveButtonPermission($arr['module'], $arr['controller'], 'add')) {
                                                        $btn['id'] = '/' . $arr['id'] . '/' . $module . '/' . $arr['controller'] . '/add';
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->addText;
                                                            }
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = $this->context->addText;
                                                        }
                                                    }
                                                    break;
                                                case 'editBtn':
                                                    //如果是编辑按钮
                                                    if (self::isHaveButtonPermission($arr['module'], $arr['controller'], 'edit')) {
                                                        $btn['id'] = '/' . $arr['id'] . '/' . $module . '/' . $arr['controller'] . '/edit';
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->editText;
                                                            }
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = $this->context->editText;
                                                        }
                                                    }
                                                    break;
                                                case 'deleteBtn':
                                                    //如果是删除按钮
                                                    if (self::isHaveButtonPermission($arr['module'], $arr['controller'], 'delete')) {
                                                        $btn['id'] = '/' . $arr['id'] . '/' . $module . '/' . $arr['controller'] . '/delete';
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->deleteText;
                                                            }
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = $this->context->deleteText;
                                                        }
                                                    }
                                                    break;
                                                case 'disabledBtn':
                                                    //如果是禁用开启按钮
                                                    if (self::isHaveButtonPermission($arr['module'], $arr['controller'], 'disabled')) {
                                                        $btn['id'] = '/' . $arr['id'] . '/' . $module . '/' . $arr['controller'] . '/disabled';
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->disabledText;
                                                            }
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = $this->context->disabledText;
                                                        }
                                                    }
                                                    break;
                                                case 'viewBtn':
                                                    //如果是详情按钮
                                                    if (self::isHaveButtonPermission($arr['module'], $arr['controller'], 'view')) {
                                                        $btn['id'] = '/' . $arr['id'] . '/' . $module . '/' . $arr['controller'] . '/view';
                                                        if (isset($params[1]) && $bv != 'show') {
                                                            $btn['text'] = trim(trim($params[1]), "'");
                                                            $btn['text'] = trim(trim($btn['text']), '"');
                                                            if ($btn['text'] == 'null') {
                                                                $btn['text'] = $this->context->viewText;
                                                            }
                                                        } else if (!isset($btn['text'])) {
                                                            $btn['text'] = $this->context->viewText;
                                                        }
                                                    }
                                                    break;
                                                case 'show':
                                                    //如果是表格编辑
                                                    if (self::isHaveButtonPermission($arr['module'], $arr['controller'], 'autopost')) {
                                                        if (isset($params[2]) && $params[2] && $params[0] != 'image') {
                                                            $btn['id']   = '/' . $arr['id'] . '/' . $module . '/' . $arr['controller'] . '/autopost';
                                                            $btn['text'] = '表格编辑自动提交';
                                                        }
                                                    }
                                                    break;
                                            }
                                        } else if (in_array($bv, ['linkBtn', 'openWindowBtn'])) {
                                            //如果是链接按钮或者打开窗口按钮
                                            if (self::isHaveButtonPermission($arr['module'], $arr['controller'], $params[0])) {
                                                if (isset($params[0])) {
                                                    $action    = trim($params[0], "'");
                                                    $action    = trim($action, '"');
                                                    $btn['id'] = '/' . $arr['id'] . '/' . $module . '/' . $arr['controller'] . '/' . $action;
                                                }
                                                if (isset($params[1])) {
                                                    $btn['text'] = trim(trim($params[1]), "'");
                                                    $btn['text'] = trim(trim($btn['text']), '"');
                                                }
                                            }
                                        }

                                        //如果按钮不为空
                                        if ($btn) {
                                            //判断按钮是否已经添加到节点中
                                            $is_exis = false;
                                            foreach ($arr['children'] as $ck => $cv) {
                                                if ($cv['id'] == $btn['id']) {
                                                    $is_exis = true;
                                                }
                                            }
                                            //如果按钮没有重复则添加到节点中
                                            if (!$is_exis) {
                                                $btn['pid']        = $arr['id'];
                                                $arr['children'][] = $btn;
                                            }
                                        }
                                    }

                                    //继续递归
                                    $arr['children'] = array_merge($arr['children'], $this->getMenuPermissionsTree($arr['id']));
                                }

                            } else {
                                $arr['children'] = [];
                            }
                        }
                    }
                } else {
                    $arr['children'] = $this->getMenuPermissionsTree($arr['id']);
                }
            }
        }

        return $data;
    }

    /**
     * 获取控制器数组
     * @Author   July
     * @DateTime 2024-01-13T20:09:31+0800
     * @param string $dir          控制器目录
     * @param string $search_file   要查找的文件
     * @param array  $files        控制器文件数组
     * @return array
     */
    public function getControllers($dir = "", $search_file = '', &$files = [])
    {
        $handle = opendir($dir);
        while ($file = readdir($handle)) {
            $type = filetype($dir . DIRECTORY_SEPARATOR . $file);
            if ($file == '.' || $file == "..") {
                continue;
            }

            if ($type == "file") {
                //如果类型为文件
                $source_file = $dir . DIRECTORY_SEPARATOR . $file;
                $ext         = explode(".", $file);
                if (count($ext) > 1) {
                    if ($ext[count($ext) - 1] == "php" && stripos($dir, "controller") > -1) {
                        if ($search_file && strtolower($file) == strtolower($search_file)) {
                            closedir($handle);
                            $files = [$source_file];
                            return;
                        }
                    }
                }
            }
            if ($type == "dir") {
                //如果类型为文件夹
                $this->getControllers($dir . DIRECTORY_SEPARATOR . $file, $search_file, $files);
            }
        }
        closedir($handle);
        return $files;
    }

    /**
     * 判断是否有按钮权限
     * @Author   July
     * @DateTime 2024-01-13T20:09:45+0800
     * @param  string  $module     模块名称
     * @param  string  $controller 控制器
     * @param  string  $action     方法
     * @return boolean             有权限返回true，否则返回false
     */
    public static function isHaveButtonPermission($module, $controller, $action)
    {
        if (!session('admininfo')) {
            return false;
        }
        if (session('admininfo.roleid') == 1) {
            return true;
        }

        //如果当前登录角色大于1，那就是非超管，获取角色拥有的权限列表
        $role_permissions = AdminRoleList::where(['role_id' => session('admininfo.roleid')])->cache('role_permissions_' . session('admininfo.roleid'), 30)->select()->toArray();
        $module           = strtolower($module);
        $controller       = strtolower($controller);
        $action           = strtolower($action);
        foreach ($role_permissions as $rpk => $rpv) {
            $rpv['controller'] = strtolower($rpv['controller']);
            $rpv['action']     = strtolower($rpv['action']);
            $rpv['module']     = strtolower($rpv['module']);
            if ($rpv['module'] == $module && $rpv['controller'] == $controller && $rpv['action'] == $action) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断菜单是否有权限
     * @Author   July
     * @DateTime 2023-06-21T23:43:48+0800
     * @param    integer                  $menu_id 菜单id
     * @return   boolean                  有权限返回true，没有返回false
     */
    public static function isHaveMenuPermission($menu_id = 0)
    {
        if (!session('admininfo')) {
            return false;
        }
        if (session('admininfo.roleid') == 1) {
            return true;
        }

        //如果当前登录角色大于1，那就是非超管，获取角色拥有的权限列表
        $role_permissions = AdminRoleList::where(['role_id' => session('admininfo.roleid')])->cache('role_permissions_' . session('admininfo.roleid'), 20)->select()->toArray();

        foreach ($role_permissions as $rpk => $rpv) {
            $menu_parent_ids = array_filter(explode(',', $rpv['menu_parent_ids']));
            if ($rpv['menu_id'] == $menu_id || in_array($menu_id, $menu_parent_ids)) {
                return true;
            }
        }
        return false;
    }
}
